/*
 * app_filetransport_api_subsidiary.c
 *
 *  Created on: 2023年8月30日
 *      Author: HXF
 */

#include "app_filetransport_api_subsidiary.h"
#include "app_filetransport_api.h"
#include "app_log.h"
#include "device.h"
#include "softwareMultiTimer.h"
#include "app_file_event_link.h"
#include "sl_malloc.h"
#include "app_key_value.h"
#include "mac_transmitter.h"
#include "em_wdog.h"
#include "device_partition.h"
#ifdef HUB_DEVICE
#include "app_hub_api.h"
#else
#if(FILE_FLASH_ENABLE)
#include "app_multislot.h"
#endif
#endif

#define CRC32_INIT  0xffffffff
#define CRC32_XOROT 0xffffffff

static const unsigned int CRC32_Table[256] =
{
   0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
   0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
   0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
   0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
   0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
   0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
   0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
   0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
   0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
   0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
   0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
   0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
   0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
   0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
   0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
   0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
   0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
   0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
   0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
   0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
   0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
   0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
   0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
   0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
   0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
   0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
   0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
   0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
   0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
   0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
   0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
   0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
   0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
   0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
   0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
   0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
   0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
   0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
   0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
   0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
   0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
   0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
   0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
   0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
   0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
   0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
   0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
   0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
   0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
   0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
   0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
   0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
   0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
   0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
   0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
   0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
   0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
   0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
   0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
   0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
   0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
   0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
   0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
   0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};

unsigned int get_msg_crc32(unsigned char *msg, int len)
{
  unsigned int crc32_value;

  if(msg == NULL || len == 0){
    return 0;
  }

  crc32_value = CRC32_INIT;
  while(len--){
      crc32_value = CRC32_Table[(crc32_value ^ *msg++) & 0xFF] ^ (crc32_value >> 8);
  }
  return (crc32_value ^ CRC32_XOROT);
}

void file_api_test(void)
{

}

#ifdef HUB_DEVICE
static ota_rfm_info_t *ptr_rfm_info = NULL;
static product_targets product_record = {0};
static custom_targets custom_record = {0};
static MultiTimer fix_50ms_to_tx_file_Timer = {.Handle = 0x06};
static MultiTimer qrfh_handshake_Timer = {.Handle = 0x07};
static uint32_t product_pre_ticks = 0;
static int product_pre_remain = 0;
static int product_page_id = 0;
#else
static custom_targets custom_record = {0};
static MultiTimer rfm_timeout_to_confirm_Timer = {.Handle = 0x06};
static MultiTimer rfm_no_rcv_timeout_Timer = {.Handle = 0x07};
static MultiTimer rfm_delay_reboot_Timer = {.Handle = 0x08};
static unsigned char *ptr_last_file = NULL;
static unsigned char last_file_id[2] = {0};
static int last_file_len = 0;
static unsigned char *ptr_verify_code = NULL;
#endif



#ifdef HUB_DEVICE
static int hub_malloc_rfm_info_buf(void)
{
  unsigned char ota_num = 0;
  unsigned char ota_id[OTA_ID_BUF_MAX] = {0};
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  if(ota_num == 0 || ota_num > OTA_ID_BUF_MAX){
      return 1;
  }
  getThisParam(ENbyPanelSetOtaId, ota_id);
  if(!ptr_rfm_info){
      ptr_rfm_info = sl_malloc(sizeof(ota_rfm_info_t) * OTA_ID_BUF_MAX);
  }
  if(ptr_rfm_info){
      memset(ptr_rfm_info, 0, sizeof(ota_rfm_info_t) * OTA_ID_BUF_MAX);
      for(unsigned char i = 0; i < ota_num; i++){
          (ptr_rfm_info+i)->rfmid = ota_id[i];
          (ptr_rfm_info+i)->enable_ota = 1;
      }
      return 0;
  }else{
     return -1;
  }
}

int hub_free_rfm_info_buf(void)
{
  if(ptr_rfm_info){
      sl_free(ptr_rfm_info);
      ptr_rfm_info = NULL;
  }
  return 0;
}

void printf_rfm_ota_info(void)
{
  if(!file_log_enable){
      return;
  }
  if(!ptr_rfm_info){
      return;
  }
  unsigned char ota_num = 0;
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  if(ota_num == 0 || ota_num > OTA_ID_BUF_MAX){
      return;
  }
  for(unsigned char i = 0; i < ota_num; i++){
      APP_PRINTF("rid: %d, en: %d, re: %d, co: %d, ch: %d, fi: %d\r\n",
             (ptr_rfm_info+i)->rfmid,
             (ptr_rfm_info+i)->enable_ota,
             (ptr_rfm_info+i)->is_request,
             (ptr_rfm_info+i)->is_confirm,
             (ptr_rfm_info+i)->is_check,
             (ptr_rfm_info+i)->is_finish);
      for(unsigned char j = 0; j < 5; j++){
          APP_PRINTF("  bid: %d, cnt: %d, [%02x%02x%02x%02x]\r\n",(ptr_rfm_info+i)->block[j].block_id,
                 (ptr_rfm_info+i)->block[j].err_count,
                 (ptr_rfm_info+i)->block[j].page_mask[0],
                 (ptr_rfm_info+i)->block[j].page_mask[1],
                 (ptr_rfm_info+i)->block[j].page_mask[2],
                 (ptr_rfm_info+i)->block[j].page_mask[3]);
      }
  }
}

static void fix_50ms_to_tx_file_TimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;
  setMacTransEvent(EN_TRANS_REQ_FILE_DATA_TX, 0xff, ADHOC_RETRY_COUNT_MAX ,LBT_REDO_COUNT_MAX);
  start_fix_time_to_tx_file_Timer();
}

static void stop_fix_50ms_to_tx_file_Timer(void)
{
  if(softwareMultiTimerFind(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &fix_50ms_to_tx_file_Timer) >= 0){
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &fix_50ms_to_tx_file_Timer, 0);
  }
}

static void start_fix_50ms_to_tx_file_Timer(int time, void *userData)
{
  stop_fix_50ms_to_tx_file_Timer();
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,
                          &fix_50ms_to_tx_file_Timer, time, fix_50ms_to_tx_file_TimerCallback, userData, 0);
}

int start_fix_time_to_tx_file_Timer(void)
{
  int time = 1639; //50ms
  start_fix_50ms_to_tx_file_Timer(time, NULL);
  return 0;
}

int stop_fix_time_to_tx_file_Timer(void)
{
  stop_fix_50ms_to_tx_file_Timer();
  return 0;
}

static void qrfh_handshake_TimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;
  creat_ota_wait_timeout_event();
}

int start_qrfh_handshake_Timer(void)
{
  int time = 11796480ul; //6 * 60 * 32768 = 6min //留了些余量
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,
                            &qrfh_handshake_Timer, time, qrfh_handshake_TimerCallback, NULL, 0);
  return 0;
}

int stop_qrfh_handshake_Timer(void)
{
  softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &qrfh_handshake_Timer, 0);
  return 0;
}

int update_ota_rfm_request_state(unsigned char rfmid, unsigned char state)
{
  unsigned char i;
  unsigned char ota_num = 0;
  if(!ptr_rfm_info){
      return -1;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->rfmid == rfmid){
          if((ptr_rfm_info + i)->enable_ota){
              (ptr_rfm_info + i)->is_request = state;
          }
          break;
      }
  }
  if(i == ota_num){
      return 1;
  }else{
      return 0;
  }
}

int update_ota_rfm_confirm_state(unsigned char rfmid, unsigned char state)
{
  unsigned char i;
  unsigned char ota_num = 0;
  if(!ptr_rfm_info){
      return -1;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->rfmid == rfmid){
          if((ptr_rfm_info + i)->enable_ota){
              (ptr_rfm_info + i)->is_confirm = state;
          }
          break;
      }
  }
  if(i == ota_num){
      return 1;
  }else{
      return 0;
  }
}

int update_ota_rfm_check_state(unsigned char rfmid, unsigned char state,
                               unsigned char *blockvalue, int len)
{
  unsigned char i,j,k;
  unsigned char ota_num = 0;
  unsigned char count = 0;
  unsigned char err_count = 0;
  unsigned char idx = 0;
  unsigned char qrfh2 = 0;

  if(!ptr_rfm_info){
      return -1;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  if(rfmid == 0xff){
      for(i = 0; i < ota_num; i++){
          if((ptr_rfm_info + i)->enable_ota){
              (ptr_rfm_info + i)->is_check = state;
          }
      }
      return 0;
  }

  if(len == 0 || len > 25){
      if(file_log_enable){
          DS_app_log_error("len err\r\n");
      }
      return -1;
  }
  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->rfmid == rfmid){
          break;
      }
  }
  if(i == ota_num){
      return 1;
  }

  if((ptr_rfm_info + i)->is_check == state){ //避免重复报文触发累加
      return 2;
  }

  if((ptr_rfm_info + i)->enable_ota){
      (ptr_rfm_info + i)->is_check = state;
  }


  if(blockvalue[0] == 0xff){ //完整的校验
      if((ptr_rfm_info + i)->enable_ota){
          if(blockvalue[1] & 0x01){
              (ptr_rfm_info + i)->is_finish = OTA_ERR_NOERR;
          }else{
              (ptr_rfm_info + i)->is_finish = OTA_ERR_SHA256;
          }
          //完成校验的rfm,清qrfh2的bit0
          getDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
          (qrfh2 &= ~(1 << 0));
          setDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
      }

      for(j = 0; j < 5; j++){
          (ptr_rfm_info + i)->block[j].block_id = 0;
          (ptr_rfm_info + i)->block[j].err_count = 0;
          for(k = 0; k < 4; k++){
              (ptr_rfm_info + i)->block[j].page_mask[k] = 0;
          }
      }
      if(file_log_enable){
          APP_PRINTF("rfmid %d en %d fi %d\r\n",
                     rfmid,(ptr_rfm_info + i)->enable_ota,(ptr_rfm_info + i)->is_finish);
      }
      return 0;
  }

  getThisParam(ENbyReadFileLinkIdx, &idx);

  for(j = 0; j < len; j = j+5){
      count = 0;
      err_count = 0;
      if(idx == FILE_LINK_1 || idx == FILE_LINK_2){
          if(blockvalue[0+j] == get_ota_production_file_link_custom_blockid()){
              for(k = 0; k < 8; k++){
                  if((blockvalue[1+j] >> k) & 1){  //置1成功，置0失败
                      count++;
                  }
                  if((blockvalue[2+j] >> k) & 1){
                      count++;
                  }
                  if((blockvalue[3+j] >> k) & 1){
                      count++;
                  }
                  if((blockvalue[4+j] >> k) & 1){
                      count++;
                  }
              }
              err_count = (get_ota_production_file_link_custom_num(blockvalue[0+j]) - count);
              (ptr_rfm_info + i)->block[j/5].err_count = err_count;
          }
          memcpy((ptr_rfm_info + i)->block[j/5].page_mask, &blockvalue[1+j], 4);
          (ptr_rfm_info + i)->block[j/5].block_id = blockvalue[0+j];
      }else{  //如果重传时出错
          for(k = 0; k < 8; k++){
              if((blockvalue[1+j] >> k) & 1){  //置1成功，置0失败
                  count++;
              }
              if((blockvalue[2+j] >> k) & 1){
                  count++;
              }
              if((blockvalue[3+j] >> k) & 1){
                  count++;
              }
              if((blockvalue[4+j] >> k) & 1){
                  count++;
              }
          }
          err_count = (ptr_rfm_info + i)->block[j/5].err_count;
          if((get_ota_production_file_link_custom_num(blockvalue[0+j]) - count) == 0){
              err_count = 0;
          }else{
              err_count += (get_ota_production_file_link_custom_num(blockvalue[0+j]) - count);
          }
          (ptr_rfm_info + i)->block[j/5].err_count = err_count;
          memcpy((ptr_rfm_info + i)->block[j/5].page_mask, &blockvalue[1+j], 4);
          (ptr_rfm_info + i)->block[j/5].block_id = blockvalue[0+j];
      }
  }

  for(j = len/5; j < 5; j++){
      (ptr_rfm_info + i)->block[j].block_id = 0;
      (ptr_rfm_info + i)->block[j].err_count = 0;
      for(k = 0; k < 4; k++){
          (ptr_rfm_info + i)->block[j].page_mask[k] = 0;
      }
  }
  if(file_log_enable){
      APP_PRINTF("rfmId[%d]: \r\n",rfmid);
      for(j = 0; j < 5; j++){
          APP_PRINTF("ID: %d, count: %d bit:\r\n",(ptr_rfm_info + i)->block[j].block_id,
                 (ptr_rfm_info + i)->block[j].err_count);
          for(k = 0; k < 4; k++){
              APP_PRINTF("%02x",(ptr_rfm_info + i)->block[j].page_mask[k]);
          }
          APP_PRINTF("\r\n");
      }
  }
  return 0;
}

int update_all_ota_rfm_finish_state(unsigned char state)
{
  unsigned char i;
  unsigned char ota_num = 0;
  unsigned char qrfh2 = 0;

  if(!ptr_rfm_info){
      return -1;
  }

  getThisParam(ENbyPanelSetOtaNum, &ota_num);

  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->enable_ota){
          (ptr_rfm_info + i)->enable_ota = (state != OTA_ERR_NOERR)?0:1;
          (ptr_rfm_info + i)->is_finish = state;
          getDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
          (qrfh2 &= ~(1 << 0));
          setDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
      }
  }
  return 0;
}

int update_ota_rfm_id_buf(void) //通知广播之前，握手阶段结束，校验结束，会调用update_ota_rfm_id_buf
{
  unsigned char i,j;
  unsigned char ota_num = 0;
  unsigned char updateme_id_num = 0;
  unsigned char updateme_id[OTA_ID_BUF_MAX] = {0};
  unsigned char block_err_count = 0;
  unsigned char block_err_max = 0;
  unsigned char qrfh2 = 0;
  FILE_TRANSPORT_E step;
  if(!ptr_rfm_info){
      return -1;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  block_err_max = ((ota_num == 1) ? (EACH_BLOCK_MAX_ERR_COUNT * 4) : EACH_BLOCK_MAX_ERR_COUNT); //单设备OTA，块文件出错次数最大值增加到128

  step = get_file_transport_step();
  for(i = 0; i < ota_num; i++){
      if(step == PRODUCTION_NOTIFY){
          if((ptr_rfm_info + i)->enable_ota){
              if(checkRFMMemSupportOTA((ptr_rfm_info + i)->rfmid) == false){  //rfm不支持ota
                  (ptr_rfm_info + i)->enable_ota = 0;
                  (ptr_rfm_info+i)->is_finish = OTA_ERR_NOT_SUPPORT;
                  //没有置过对qrfh2的bit0，不需要清
                  //printf("Not Support\r\n");
              }else{
                  //printf("Support\r\n");
              }
          }
      }else if(step == PRODUCTION_HANDSHAKE){
          if((ptr_rfm_info + i)->enable_ota){
              if(!((ptr_rfm_info + i)->is_request) || !((ptr_rfm_info + i)->is_confirm)){ //握手失败
                  (ptr_rfm_info+i)->enable_ota = 0;
                  (ptr_rfm_info+i)->is_finish = OTA_ERR_HANDSHAKE_CONN;
                  //被剔除的rfm,清qrfh2的bit0
                  getDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
                  (qrfh2 &= ~(1 << 0));
                  setDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
              }
          }
      }else if(step == PRODUCTION_TRANSPORT_CHECK){
          if((ptr_rfm_info+i)->enable_ota){
              if(!((ptr_rfm_info + i)->is_check)){ //校验没收到
                  (ptr_rfm_info+i)->enable_ota = 0;
                  (ptr_rfm_info+i)->is_finish = OTA_ERR_CHECK_CONN;
                  //被剔除的rfm,清qrfh2的bit0
                  getDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
                  (qrfh2 &= ~(1 << 0));
                  setDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
              }else{
                  block_err_count = 0;
                  for(j = 0; j < 5; j++){
                      if((ptr_rfm_info+i)->block[j].err_count){
                          if((ptr_rfm_info+i)->block[j].err_count > block_err_max){ //任意一块文件出错大于32次
                              (ptr_rfm_info+i)->enable_ota = 0;
                              (ptr_rfm_info+i)->is_finish = OTA_ERR_TOO_MANY_COUNT;
                              //被剔除的rfm,清qrfh2的bit0
                              getDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
                              (qrfh2 &= ~(1 << 0));
                              setDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
                              break;
                          }
                          block_err_count++;
                          if(block_err_count == 5){  //5块文件都出错
                              (ptr_rfm_info+i)->enable_ota = 0;
                              (ptr_rfm_info+i)->is_finish = OTA_ERR_TOO_MANY_BLOCK;
                              //被剔除的rfm,清qrfh2的bit0
                              getDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
                              (qrfh2 &= ~(1 << 0));
                              setDeviceParam((ptr_rfm_info+i)->rfmid, ENpbyNodeQrfH2First, &qrfh2);
                              break;
                          }
                      }
                  }
              }
          }
      }
      if((ptr_rfm_info+i)->enable_ota){
          updateme_id[updateme_id_num++] = (ptr_rfm_info+i)->rfmid;
      }
  }
  setThisParam(ENbyOtaUpdatemeIDNum, &updateme_id_num);
  setThisParam(ENbyOtaUpdatemeID, updateme_id);
  return 0;
}

void ota_init_production(void)
{
  unsigned char file_size[4] = {0x00};
  unsigned char page_size = 0;
  int size = 0;

  get_file_file_size(file_size);
  get_file_page_size(&page_size);
  size = (file_size[0] << 24) + (file_size[1] << 16) + (file_size[2] << 8) + (file_size[3]);

  memset(&product_record, 0, sizeof(product_targets));
  product_record.file_page_num = ((size % page_size) == 0)?(size / page_size):((size / page_size)+1);
  product_record.remain_f_p_num = product_record.file_page_num;

  memset(&custom_record, 0, sizeof(custom_targets));
  custom_record.file_page_num = ((size % page_size) == 0)?(size / page_size):((size / page_size)+1);
  custom_record.remain_f_c_num = custom_record.file_page_num;
  custom_record.block_idx_pre = 0xff; //既不是FILE_LINK_1，也不是FILE_LINK_2

  product_pre_ticks = READ_SYS_RTC_COUNT();
  product_page_id = 0;

  if(file_log_enable){
      APP_PRINTF("file page num %d, remain %d\r\n",product_record.file_page_num, product_record.remain_f_p_num);
  }
}

int ota_update_production_progress(FILE_LINK_NUM_E num)
{
  if(num != FILE_LINK_1 && num != FILE_LINK_2){
      return -1;
  }
  if(product_record.remain_f_p_num){
      product_record.remain_f_p_num--;
  }else{
      return 1;
  }
  if(product_record.remain_b_p_num[num]){
      product_record.remain_b_p_num[num]--;
  }else{
      return 2;
  }
  return 0;
}

int get_ota_production_block_num(FILE_LINK_NUM_E num)
{
  if(num != FILE_LINK_1 && num != FILE_LINK_2){
      return 0;
  }
  return product_record.block_page_num[num];
}

int get_ota_production_blockid(void)
{
  unsigned char idx = 0;
  getThisParam(ENbyWriteFileLinkIdx, &idx);
  if(idx != FILE_LINK_1 && idx != FILE_LINK_2){
      return 0;
  }
  return product_record.block_id[idx];
}

static bool check_ota_history_cache_is_too_many(void)
{
  unsigned char block_id[5] = {0x00};
  unsigned char block_count = 0;
  unsigned char idx, i;
  unsigned char cache_len = 0;
  cache_page_file_t page_msg = {0};
  int page_msg_len = 0;
  cache_len = file_cache_link_len(FILE_LINK_HISTORY);
  if(cache_len >= HISTORY_LINK_HAVE_MAX_PAGE_NUM){
      return true;
  }

  for(idx = 0; idx < cache_len; idx++){
      file_cache_link_find_by_idx(FILE_LINK_HISTORY, (unsigned char *)&page_msg, &page_msg_len, idx);
      for(i = 0; i < 5; i++){
          if(page_msg.block_id != block_id[i]){
              if(block_id[i] == 0){
                  block_id[i] = page_msg.block_id;
                  block_count++;
                  break;
              }
          }else if(page_msg.block_id == block_id[i]){
              break;
          }
      }
      if(block_count >= HISTORY_LINK_HAVE_MAX_BLOCK){
          return true;
      }
  }
  return false;
}

bool check_ota_start_production(void)
{
  unsigned char idx = 0;
  unsigned char blockid = 0;

  if(product_record.remain_f_p_num == 0){
      return false;
  }

  if(check_ota_history_cache_is_too_many()){
      return false;
  }

  blockid = ((product_record.file_page_num - product_record.remain_f_p_num)/EACH_BLOCK_HAVE_MAX_PAGE_NUM+1);
  if(blockid % 2){
      if(file_cache_link_len(FILE_LINK_2) >= EACH_BLOCK_HAVE_MAX_PAGE_NUM){ //缓存区2还没开始消费，缓存区1先不生产
          return false;
      }
      if(file_cache_link_is_empty(FILE_LINK_1) == false){ //缓存区1还没消费完
          return false;
      }
      idx = FILE_LINK_1;
      setThisParam(ENbyWriteFileLinkIdx, &idx);

      product_record.block_page_num[FILE_LINK_1] =
          (product_record.remain_f_p_num >= EACH_BLOCK_HAVE_MAX_PAGE_NUM) ?
              EACH_BLOCK_HAVE_MAX_PAGE_NUM : product_record.remain_f_p_num;
      product_record.remain_b_p_num[FILE_LINK_1] = product_record.block_page_num[FILE_LINK_1];
      product_record.block_id[FILE_LINK_1] = blockid;
      return true;
  }else{
      if(file_cache_link_len(FILE_LINK_1) >= EACH_BLOCK_HAVE_MAX_PAGE_NUM){ //缓存区1还没开始消费，缓存区2先不生产
          return false;
      }
      if(file_cache_link_is_empty(FILE_LINK_2) == false){ //缓存区2还没消费完
          return false;
      }
      idx = FILE_LINK_2;
      setThisParam(ENbyWriteFileLinkIdx, &idx);

      product_record.block_page_num[FILE_LINK_2] =
          (product_record.remain_f_p_num >= EACH_BLOCK_HAVE_MAX_PAGE_NUM) ?
              EACH_BLOCK_HAVE_MAX_PAGE_NUM : product_record.remain_f_p_num;
      product_record.remain_b_p_num[FILE_LINK_2] = product_record.block_page_num[FILE_LINK_2];
      product_record.block_id[FILE_LINK_2] = blockid;
      return true;
  }
}

bool check_ota_suspend_production(void)
{
  unsigned char idx = 0;
  getThisParam(ENbyWriteFileLinkIdx, &idx);
  if(product_record.remain_b_p_num[idx] == 0){
      return true;
  }
  return false;
}

bool check_ota_finish_production(void)
{
  if(product_record.remain_f_p_num == 0){
      return true;
  }
  return false;
}

bool check_ota_production_no_run(void)
{
  uint32_t product_now_ticks = 0;
  uint32_t diff_ticks = 0;
  if(product_record.remain_f_p_num == 0){
      return false;
  }
  if(product_pre_remain != product_record.remain_f_p_num){
      product_pre_remain = product_record.remain_f_p_num;
      product_pre_ticks = READ_SYS_RTC_COUNT();
  }
  product_now_ticks = READ_SYS_RTC_COUNT();
  if(product_now_ticks >= product_pre_ticks){
      diff_ticks = product_now_ticks - product_pre_ticks;
  }else{
      diff_ticks = product_now_ticks - product_pre_ticks + 1 + 0xffffffffUL;
  }
  if(diff_ticks > 655360ul){ //意味着超过20S没有收到panel的文件了,按照异常处理
      return true;
  }
  return false;
}

bool check_file_is_exist_in_filelink(unsigned char *pageid, FILE_LINK_NUM_E num)
{
  if(num != FILE_LINK_1 && num != FILE_LINK_2){
      return false;
  }
  if(!pageid){
      return false;
  }
  cache_page_file_t file_msg = {0};
  int file_msg_len = 0;

  if(!file_cache_link_find_by_pageid(num, (unsigned char *)&file_msg, &file_msg_len, pageid)){
      return true;
  }
  if(!file_cache_link_find_by_pageid(FILE_LINK_HISTORY, (unsigned char *)&file_msg, &file_msg_len, pageid)){
      return true;
  }
  return false;
}

bool check_ota_rfm_all_request(void)
{
  unsigned char i;
  unsigned char ota_num = 0;
  if(!ptr_rfm_info){
      return false;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->enable_ota){
          if((ptr_rfm_info + i)->is_request == 0){
              break;
          }
      }
  }
  if(i == ota_num){
      return true;
  }else{
      return false;
  }
}

bool check_ota_rfm_all_confirm(void)
{
  unsigned char i;
  unsigned char ota_num = 0;
  if(!ptr_rfm_info){
      return false;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->enable_ota){
          if((ptr_rfm_info + i)->is_confirm == 0){
              break;
          }
      }
  }
  if(i == ota_num){
      return true;
  }else{
      return false;
  }
}

bool check_ota_rfm_all_check(void)
{
  unsigned char i;
  unsigned char ota_num = 0;
  if(!ptr_rfm_info){
      return false;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->enable_ota){
          if((ptr_rfm_info + i)->is_check == 0){
              break;
          }
      }
  }
  if(i == ota_num){
      return true;
  }else{
      return false;
  }
}

bool check_ota_rfm_all_finish(void)
{
  unsigned char i;
  unsigned char ota_num = 0;
  if(!ptr_rfm_info){
      return false;
  }
  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  for(i = 0; i < ota_num; i++){
      if(file_log_enable){
          APP_PRINTF("idx %d, en %d finish %d\r\n",i,(ptr_rfm_info + i)->enable_ota,(ptr_rfm_info + i)->is_finish);
      }
      if((ptr_rfm_info + i)->enable_ota){
          if((ptr_rfm_info + i)->is_finish == 0){
              break;
          }
      }
  }

  if(i == ota_num){
      return true;
  }else{
      return false;
  }
}

bool check_ota_need_abort(void)
{
  unsigned char updateme_id_num = 0;
  getThisParam(ENbyOtaUpdatemeIDNum, &updateme_id_num);
  return (updateme_id_num)?false:true;
}

int ota_update_custom_progress(void)
{
  unsigned char idx = 0;
  getThisParam(ENbyReadFileLinkIdx, &idx);
  if(idx == FILE_LINK_HISTORY){
      if(custom_record.remain_b_c_num){
          custom_record.remain_b_c_num--;
      }else{
          return 1;
      }
  }else{
      if(custom_record.remain_f_c_num){
          custom_record.remain_f_c_num--;
      }else{
          return 2;
      }
      if(custom_record.remain_b_c_num){
          custom_record.remain_b_c_num--;
      }else{
          return 3;
      }
  }
  if(file_log_enable){
      APP_PRINTF("remain_c_num: f %d, b(%d) %d\r\n",
                 custom_record.remain_f_c_num, idx, custom_record.remain_b_c_num);
  }
  return 0;
}

bool check_ota_start_custom(void)
{
  unsigned char idx = 0;

  if(check_ota_history_cache_is_too_many()){
      custom_record.remain_b_c_num = file_cache_link_len(FILE_LINK_HISTORY);
      idx = FILE_LINK_HISTORY;
      setThisParam(ENbyReadFileLinkIdx, &idx);
      return true;
  }

  if(!custom_record.remain_f_c_num){
      if(file_cache_link_len(FILE_LINK_HISTORY)){
          custom_record.remain_b_c_num = file_cache_link_len(FILE_LINK_HISTORY);
          idx = FILE_LINK_HISTORY;
          setThisParam(ENbyReadFileLinkIdx, &idx);
          return true;
      }else{
          return false;
      }
  }

  if(custom_record.block_idx_pre == FILE_LINK_1){
      custom_record.remain_b_c_num =  (custom_record.remain_f_c_num >= EACH_BLOCK_HAVE_MAX_PAGE_NUM) ?
          EACH_BLOCK_HAVE_MAX_PAGE_NUM : custom_record.remain_f_c_num;
      custom_record.block_page_num = custom_record.remain_b_c_num;
      idx = FILE_LINK_2;
      //APP_PRINTF("idx %d remain %d\r\n",idx,custom_record.remain_b_c_num);
      setThisParam(ENbyReadFileLinkIdx, &idx);
      return true;
  }else {
      custom_record.remain_b_c_num =  (custom_record.remain_f_c_num >= EACH_BLOCK_HAVE_MAX_PAGE_NUM) ?
          EACH_BLOCK_HAVE_MAX_PAGE_NUM : custom_record.remain_f_c_num;
      custom_record.block_page_num = custom_record.remain_b_c_num;
      idx = FILE_LINK_1;
      //APP_PRINTF("idx %d remain %d\r\n",idx,custom_record.remain_b_c_num);
      setThisParam(ENbyReadFileLinkIdx, &idx);
      return true;
  }
  return false;
}

bool check_ota_suspend_custom(void)
{
  unsigned char idx = 0;
#if(0)
  if(!custom_record.remain_f_c_num){
      return true;
  }
#endif
  getThisParam(ENbyReadFileLinkIdx, &idx);
  if(idx == FILE_LINK_1 || idx == FILE_LINK_2){
      custom_record.block_idx_pre = idx;
      //APP_PRINTF("idx: %d bp: %d bc %d\r\n",idx,product_record.remain_b_p_num[idx],custom_record.remain_b_c_num);
      if((!product_record.remain_b_p_num[idx]) && (!custom_record.remain_b_c_num)){
          return true;
      }
  }else{
      if(!custom_record.remain_b_c_num){
          return true;
      }
  }
  return false;
}

int get_ota_production_file_link_custom_num(unsigned char blockid)
{
  if((blockid * EACH_BLOCK_HAVE_MAX_PAGE_NUM) <= custom_record.file_page_num){
      return EACH_BLOCK_HAVE_MAX_PAGE_NUM;
  }else{
      return (custom_record.file_page_num % EACH_BLOCK_HAVE_MAX_PAGE_NUM);
  }
}

void set_ota_production_file_link_custom_blockid(unsigned char blockid)
{
  custom_record.block_id = blockid;
}

int get_ota_production_file_link_custom_blockid(void)
{
  return custom_record.block_id;
}

int update_history_file_link(void)
{
  unsigned char ota_num = 0;
  unsigned char frist_enable = 0;
  int i = 0;
  int j = 0;
  int k = 0;
  int pageid = 0;
  int id_buf_len = 0;
  int cache_len = 0;
  cache_page_file_t page_msg = {0};
  int page_msg_len = 0;

  unsigned char info_buf[5][4] = {0x00}; //5块*4byte
  unsigned char id_buf[160][2] = {0x00}; // 5块*32page
  unsigned char temp = 0xff;

  if(!ptr_rfm_info){
      return 1;
  }

  getThisParam(ENbyPanelSetOtaNum, &ota_num);
  if(ota_num == 0 || ota_num > OTA_ID_BUF_MAX){
      return 2;
  }

  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->enable_ota){
          frist_enable = i;
          break;
      }
  }

  if(i == ota_num){
      return 3;
  }
  //APP_PRINTF("info: ");
  for(i = 0; i < 5; i++){
      for(j = 0; j < 4; j++){
          temp = 0xff;
          for(k = frist_enable; k < ota_num; k++){
              if((ptr_rfm_info + k)->enable_ota){
                  temp = temp & (ptr_rfm_info + k)->block[i].page_mask[j];
              }
          }
          info_buf[i][j] = temp;
          //APP_PRINTF("%02x ",info_buf[i][j]);
      }
  }
  //APP_PRINTF("\r\n");
  for(i = 0; i < 5; i++){
      for(j = 0; j < 4; j++){
          for(k = 0; k < 8; k++){
              if(info_buf[i][j] & (1 << k)){
                  pageid = ((ptr_rfm_info + frist_enable)->block[i].block_id - 1) * EACH_BLOCK_HAVE_MAX_PAGE_NUM
                      +  j * 8 + k + 1;
                  id_buf[id_buf_len][0] = (pageid >> 8)&0xff;
                  id_buf[id_buf_len][1] = (pageid )&0xff;
                  id_buf_len++;
              }
          }
      }
  }
  //APP_PRINTF("id_buf_len %d\r\n",id_buf_len);
  //for(int i = 0; i < id_buf_len; i++){
  //    APP_PRINTF("page%d id:%d\r\n",i,((id_buf[i][0] << 8)+id_buf[i][1]));
  //}
  cache_len = file_cache_link_len(FILE_LINK_HISTORY);
  if(file_log_enable){
      APP_PRINTF("before %d\r\n",cache_len);
  }
  for(i = 0; i < cache_len; i++){
      if(file_cache_link_pop(FILE_LINK_HISTORY, (unsigned char *)&page_msg, &page_msg_len) == 0){
          for(j = 0; j < id_buf_len; j++){
              if((page_msg.page_id[0] == id_buf[j][0]) &&
                  (page_msg.page_id[1] == id_buf[j][1])){
                  break;
              }
          }
          if(j == id_buf_len){
              file_cache_link_push(FILE_LINK_HISTORY, (unsigned char *)&page_msg, page_msg_len);
          }
      }
  }
  if(file_log_enable){
      APP_PRINTF("after %d\r\n",file_cache_link_len(FILE_LINK_HISTORY));
  }
  return 0;
}

void ota_custom_cache_history(FILE_LINK_NUM_E num, unsigned char *ptr_file, int len)
{
  //历史文件也重新写入历史文件链表
  //if(num == FILE_LINK_HISTORY){
  //    return;
  //}
  if(num != FILE_LINK_1 && num != FILE_LINK_2 && num != FILE_LINK_HISTORY){
      return;
  }
  if(!ptr_file || len == 0){
      return;
  }
  file_cache_link_push(FILE_LINK_HISTORY, ptr_file, len);
}

void creat_ota_finish_evt_to_panel(void)
{
  unsigned char data[258] = {0};  //个数: 1 + cat: 1 + NO:128+ result:128
  int len = 0;
  int i = 0;
  unsigned char ota_num = 0;
  unsigned char count = 0;
  unsigned char cat = 0x00;
  unsigned char no = 0x00;
  getThisParam(ENbyPanelSetOtaNum, &ota_num);

  if(ota_num == 0 || ota_num > OTA_ID_BUF_MAX){
      return;
  }

  if(!ptr_rfm_info){
      return;
  }
  cat = get_cat_from_rfmid((ptr_rfm_info + 0)->rfmid);
  data[len++] = count; //个数:
  data[len++] = cat; //cat

  for(i = 0; i < ota_num; i++){
      if((ptr_rfm_info + i)->is_finish != OTA_ERR_NOERR){
          no = get_no_from_cat_rfmid(cat, (ptr_rfm_info + i)->rfmid);
          data[len++] = no;
          data[len++] = (ptr_rfm_info + i)->is_finish;
          count++;
      }
  }
  if(count){
      data[0] = count;
  }else{
      len = 1;
  }
  DS_hub_api_creat_file_event(FILE_FINISH_TRANSPORT, data, len);
}

#else
void ota_init_custom(void)
{
  unsigned char file_size[4] = {0x00};
  unsigned char page_size = 0;
  int size = 0;

  get_file_file_size(file_size);
  get_file_page_size(&page_size);
  size = (file_size[0] << 24) + (file_size[1] << 16) + (file_size[2] << 8) + (file_size[3]);

  if(file_size == 0 || size == 0){
      creat_ota_abort_event();
      return;
  }

  memset(&custom_record, 0, sizeof(custom_targets));
  custom_record.file_page_num = ((size % page_size) == 0)?(size / page_size):((size / page_size)+1);

  custom_record.remain_f_c_num = custom_record.file_page_num;
  custom_record.verify_mode = FILE_VERIFY_UNKNOWN;
  if(file_log_enable){
      APP_PRINTF("file page num %d, remain %d, size %d\r\n",custom_record.file_page_num, custom_record.remain_f_c_num, size);
  }

  if(!ptr_last_file){
      ptr_last_file = sl_malloc(page_size *2);
  }
  if(!ptr_last_file){ //申请不出，异常
      creat_ota_abort_event();
  }else{
      memset(ptr_last_file, 0, (page_size *2));
      last_file_len = 0;
  }
}

static int ota_find_empty_custom_record_block_info(void)
{
  int i = 0;
  for(i = 0; i < 5; i++){
      if(custom_record.block_info[i].block_id == 0){
          return i;
      }
  }
  return 0xff;
}

static int ota_clean_custom_record_block_info(void)
{
  int i = 0;
  unsigned min_id = 0xff;
  unsigned min_id_idx = 0xff;

  for(i = 0; i < 5; i++){
      if(custom_record.block_info[i].b_result_info[0] == 0xff &&
          custom_record.block_info[i].b_result_info[1] == 0xff &&
          custom_record.block_info[i].b_result_info[2] == 0xff &&
          custom_record.block_info[i].b_result_info[3] == 0xff){
          if(custom_record.block_info[i].block_id < min_id){
              min_id = custom_record.block_info[i].block_id;
              min_id_idx = i;
          }
      }else{

      }
  }
  if(min_id_idx < 5){
      memset(&custom_record.block_info[min_id_idx], 0, sizeof(custom_block_info));
      return 0;
  }
  return 1;
}

static bool deal_gbl_tag(void)
{
  int i = 0;
  unsigned char tag_num = 0;
  int tag_id = 0; //小端：0x06B729CD，对应sha-256校验
  int tag_length = 0;

  if(!ptr_last_file || last_file_len < 4){
      return false;
  }

  tag_num = (ptr_last_file[last_file_len - 1] << 24) +
      (ptr_last_file[last_file_len - 2] << 16) +
      (ptr_last_file[last_file_len - 3] << 8) +
      (ptr_last_file[last_file_len - 4]);
  if(file_log_enable){
      APP_PRINTF("tag_num: %d\r\n",tag_num);
  }
  last_file_len -= 4;

  while((tag_num) && (last_file_len > 8)){
      tag_id = (ptr_last_file[last_file_len - 1] << 24) +
          (ptr_last_file[last_file_len - 2] << 16) +
          (ptr_last_file[last_file_len - 3] << 8) +
          (ptr_last_file[last_file_len - 4]);
      last_file_len -= 4;
      if(file_log_enable){
          APP_PRINTF("tag_id: 0x%08x\r\n",tag_id);
      }
      tag_length = (ptr_last_file[last_file_len - 1] << 24) +
          (ptr_last_file[last_file_len - 2] << 16) +
          (ptr_last_file[last_file_len - 3] << 8) +
          (ptr_last_file[last_file_len - 4]);
      last_file_len -= 4;
      if(file_log_enable){
          APP_PRINTF("tag_length: %d\r\n",tag_length);
      }
      if(tag_length > last_file_len || tag_length <= 0){ //异常的tag长度
          break;
      }
      if(tag_id == 0x06B729CD){
          custom_record.verify_mode = FILE_VERIFY_SHA256;//设置校验方式为sha-256
          if(!ptr_verify_code){
              ptr_verify_code = sl_malloc(tag_length);
          }
          if(!ptr_verify_code){
              creat_ota_abort_event();
              return false;
          }else{
              memset(ptr_verify_code, 0, tag_length);
              for(i = 0; i < tag_length; i++){
                  ptr_verify_code[i] = ptr_last_file[last_file_len - (1 + i)];
              }
              if(file_log_enable){
                  DS_app_log_hexdump_error("verify_code",ptr_verify_code,tag_length);
              }
          }
      }else{
      }
      last_file_len -= tag_length;
      tag_num--;
  }
  return true;
}

bool deal_file_payload(unsigned char *pageid, unsigned char *file, int file_len,
                       unsigned char *valid_pageid, unsigned char *valid_file,
                       int *valid_len)
{
  int page_id = 0;
  int block_id = 0;
  int idx = 0;

  int i = 0;
  unsigned char page_id_temp = 0;
  unsigned char byte_idx = 0;
  unsigned char bit_idx = 0;

  unsigned char page_size = 0;
  if(!pageid || !file || !file_len){
      return false;
  }

  block_id = get_blockid_by_pageid(pageid);
  for(i = 0; i < 5; i++){
      if(custom_record.block_info[i].block_id == block_id){
          break;
      }
  }
  if(i == 5){
      idx = ota_find_empty_custom_record_block_info(); //查找记录里的空位置
      if(idx == 0xff){ //没找到
          ota_clean_custom_record_block_info(); //删除完成最早的记录
          idx = ota_find_empty_custom_record_block_info(); //再查找一下
      }
      if(idx == 0xff){ //没有存放的位置
          if(file_log_enable){
              APP_PRINTF("block record error\r\n");
          }
          return false;
      }
  }else{
      idx = i;
  }

  page_id = (pageid[0] << 8) + pageid[1];
  page_id_temp = (page_id - ((block_id - 1)*EACH_BLOCK_HAVE_MAX_PAGE_NUM)- 1);

  byte_idx = page_id_temp /8;
  bit_idx = page_id_temp %8;

  custom_record.block_info[idx].block_id = block_id;
  custom_record.block_info[idx].b_result_info[byte_idx] |= (1 << bit_idx);
  if(custom_record.remain_f_c_num){
      custom_record.remain_f_c_num--;
  }
  if(file_log_enable){
      APP_PRINTF("remain: %d, bid:%d, [%d]info[%02x %02x %02x %02x]\r\n",
                 custom_record.remain_f_c_num,
                 custom_record.block_info[idx].block_id,
                 idx,
                 custom_record.block_info[idx].b_result_info[0],
                 custom_record.block_info[idx].b_result_info[1],
                 custom_record.block_info[idx].b_result_info[2],
                 custom_record.block_info[idx].b_result_info[3]);
  }

  if(page_id == (custom_record.file_page_num - 1)){ //当前是最后第二包
      last_file_id[0] = pageid[0];
      last_file_id[1] = pageid[1];
      if(ptr_last_file){
          //文件保存到ptr_file
          if(last_file_len == 0){
              //等拼完包之后再处理
              memcpy(ptr_last_file, file, file_len);
              last_file_len += file_len;
              return false;
          }else{
              memcpy(ptr_last_file, file, file_len);
              last_file_len += file_len;
          }
          //最后两包拼包之后处理
          if(deal_gbl_tag() == false){
              return false;
          }
          if(last_file_len == 0){
              return false;
          }
          *valid_len = last_file_len;
          memcpy(valid_file, ptr_last_file, *valid_len);
          valid_pageid[0] = last_file_id[0];
          valid_pageid[1] = last_file_id[1];
      }
  }else if(page_id == custom_record.file_page_num){ //当前是最后一包
      if(ptr_last_file){
          if(last_file_len == 0){
              //说明丢了最后第二包,等拼完包之后再处理
              get_file_page_size(&page_size);
              //预留page_size位置给最后第二包
              memcpy((ptr_last_file + page_size), file, file_len);
              last_file_len += file_len;
              return false;
          }else{
              memcpy((ptr_last_file + last_file_len), file, file_len);
              last_file_len += file_len;
          }
          //最后两包拼包之后处理
          if(deal_gbl_tag() == false){
              return false;
          }
          if(last_file_len == 0){
              return false;
          }
          *valid_len = last_file_len;
          memcpy(valid_file, ptr_last_file, *valid_len);
          valid_pageid[0] = last_file_id[0];
          valid_pageid[1] = last_file_id[1];
      }
  }else{
      *valid_len = file_len;
      memcpy(valid_file, file, *valid_len);
      valid_pageid[0] = pageid[0];
      valid_pageid[1] = pageid[1];
  }
  if(file_log_enable){
      APP_PRINTF("valid id:[%d], len %d\r\n",((valid_pageid[0] << 8) + valid_pageid[1]),*valid_len);
  }
  return true;
}

unsigned char get_custom_file_verify_mode(void)
{
  return custom_record.verify_mode;
}

unsigned char*  get_custom_file_verify_code(void)
{
  return ptr_verify_code;
}

bool check_custom_receve_file_finish(void)
{
  return((custom_record.remain_f_c_num == 0)?true:false);
}

void set_custom_file_finish_flag(unsigned char flag)
{
  custom_record.finish_flag = flag;
}

unsigned char get_custom_file_finish_flag(void)
{
  return custom_record.finish_flag;
}

int packet_check_response(unsigned char *packet, unsigned char *packet_len)
{
  int i = 0;
  unsigned char packet_idx = 0;

  if(get_custom_file_finish_flag() == 0){
      packet[packet_idx++] = 0;
      for(i = 0; i < 5; i++){
          if(custom_record.block_info[i].block_id){
              memcpy(&packet[packet_idx],
                     &custom_record.block_info[i].block_id,
                     sizeof(custom_block_info));
              packet_idx += sizeof(custom_block_info);
          }
      }
      if(packet_idx == 1){
          *packet_len = 0;
      }else{
          packet[0] = packet_idx - 1;
          *packet_len = packet_idx;
      }
  }else{
      packet[0] = 2;
      packet[1] = 0xff;
      packet[2] = (get_custom_file_finish_flag() == 1)?1:0; //1成功 0失败
      *packet_len = 3;
  }
  if(file_log_enable){
      DS_app_log_hexdump_error("[check]",packet,*packet_len);
  }
  return 0;
}

static void timeout_to_confirm_TimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;
  FILE_TRANSPORT_E step;
  keyValue_t keyvalue;

  step = get_file_transport_step();
  if(step == CONSUMPTION_REQUEST || step == CONSUMPTION_CONFIRM){
      //推送物模型
      keyvalue.id = 0xfd;
      keyvalue.valueSize = OTA_CONFIRM_VALUE_LENGTH;
      getThisParam(ENbyOtaConfirmKeyValue, &keyvalue.value);
      set_key_value(&keyvalue);
  }

  creat_ota_wait_finish_event();
}

static void stop_timeout_to_confirm_Timer(void)
{
  if(softwareMultiTimerFind(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_timeout_to_confirm_Timer) >= 0){
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_timeout_to_confirm_Timer, 0);
  }
}

static void start_timeout_to_confirm_Timer(int time, void *userData)
{
  stop_timeout_to_confirm_Timer();
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_timeout_to_confirm_Timer, time, timeout_to_confirm_TimerCallback, userData, 0);
}

static int get_trigger_confirm_time(void)
{
  unsigned char rfmid = 0;
  int i = 0;
  int time = 0;
  FILE_TRANSPORT_E step;

  unsigned char updateme_id_num = 0;
  unsigned char updateme_id[OTA_ID_BUF_MAX] = {0};

  step = get_file_transport_step();
  if(step == CONSUMPTION_REQUEST){ //此时还处于 CONSUMPTION_REQUEST阶段
      getThisParam(ENpbyRfmId, &rfmid);
      getThisParam(ENbyOtaUpdatemeID, updateme_id);      //ota ID[]
      getThisParam(ENbyOtaUpdatemeIDNum, &updateme_id_num);     //ota ID长度
      for(i = 0; i < updateme_id_num; i++){
          if(updateme_id[i] == rfmid){
              break;
          }
      }
      if(i != updateme_id_num){
          time = (updateme_id_num)* RFM_LINEUP_INTERVAL;
      }
  }
  return time;
}

int start_timer_to_trigger_confirm(void)
{
  int time = 0;
  time = get_trigger_confirm_time();
  if(!time){
      return 1;
  }
  start_timeout_to_confirm_Timer(time, NULL);
  return 0;
}

static void no_rcv_timeout_TimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;

  creat_ota_wait_timeout_event();
}

static void stop_no_rcv_timeout_Timer(void)
{
  if(softwareMultiTimerFind(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_no_rcv_timeout_Timer) >= 0){
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_no_rcv_timeout_Timer, 0);
  }
}

static void start_no_rcv_timeout_Timer(int time, void *userData)
{
  stop_no_rcv_timeout_Timer();
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_no_rcv_timeout_Timer, time, no_rcv_timeout_TimerCallback, userData, 0);
}

int start_timer_to_check_no_rcv_timeout(void)
{
  int time = RFM_WAIT_FILE_TIMEOUT;
  start_no_rcv_timeout_Timer(time, NULL);
  return 0;
}

static void delay_app_install_and_reboot_TimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;
#if(FILE_FLASH_ENABLE)
  app_install_and_reboot();
#endif
}

int start_timer_to_delay_app_install_and_reboot(void)
{
  int time = RFM_DELAY_REBOOT_TIMEOUT;
  softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_delay_reboot_Timer, 0);
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &rfm_delay_reboot_Timer, time, delay_app_install_and_reboot_TimerCallback, NULL, 0);
  return 0;
}

#endif

void ota_enter_hook(void)
{
  unsigned char i;

  unsigned char request_keyvalue[OTA_REQUEST_VALUE_LENGTH] = {0};
  unsigned char confirm_keyvalue[OTA_CONFIRM_VALUE_LENGTH] = {0};
  unsigned char consult_keyvalue[OTA_CONSULT_KEYVALUE_LENGTH] = {0};

  unsigned char flag = 0;
  unsigned char idx = FILE_LINK_1;

  if(my_transport_role(FTYPE_OTA) == PRODUCTION_ROLE){//生产者
      for(i = 0; i < NODE_MAX_COUNT; i++){
          setDeviceParam(i, ENbyOtaConSultFlag, &flag);
      }
#ifdef HUB_DEVICE
      if(hub_malloc_rfm_info_buf() != 0){
          ota_abort_hook();
          return;
      }
      file_cache_link_delte(FILE_LINK_2);
      file_cache_link_delte(FILE_LINK_HISTORY);
#endif
  }else if(my_transport_role(FTYPE_OTA) == CONSUMPTION_ROLE){//消费者

      setThisParam(ENbyOtaRequestFlag, &flag);
      setThisParam(ENbyOtaRequestKeyValue, request_keyvalue);
      setThisParam(ENbyOtaConfirmFlag, &flag);
      setThisParam(ENbyOtaConfirmKeyValue, confirm_keyvalue);
      //消费者没有consult_keyvalue flag
      setThisParam(ENbyOtaConSultKeyValue, consult_keyvalue);
  }else{
      return;
  }
  file_cache_link_delte(FILE_LINK_1);
  setThisParam(ENbyWriteFileLinkIdx, &idx);
  setThisParam(ENbyReadFileLinkIdx, &idx);
  creat_ota_start_event();
}

void ota_abort_hook(void)
{
  unsigned char i;

  unsigned char mode = OTA_MODE_NO_OTA;
  unsigned char id_buf[OTA_ID_BUF_MAX] = {0};

  unsigned char request_keyvalue[OTA_REQUEST_VALUE_LENGTH] = {0};
  unsigned char confirm_keyvalue[OTA_CONFIRM_VALUE_LENGTH] = {0};

  unsigned char flag = 0;
  unsigned char num = 0;

  unsigned char file_type = 0;
  unsigned char consult_keyvalue[OTA_CONSULT_KEYVALUE_LENGTH] = {0};
  unsigned char idx = FILE_LINK_1;

  if(my_transport_role(FTYPE_OTA) == PRODUCTION_ROLE){//生产者
#ifdef HUB_DEVICE
      printf_rfm_ota_info();
      creat_ota_finish_evt_to_panel();
      hub_free_rfm_info_buf();
      file_cache_link_delte(FILE_LINK_2);
      file_cache_link_delte(FILE_LINK_HISTORY);
#endif
      setThisParam(ENbyPanelSetOtaMode, &mode);
      setThisParam(ENbyPanelSetOtaNum, &num);
      setThisParam(ENbyPanelSetOtaId, id_buf);
      for(i = 0; i < NODE_MAX_COUNT; i++){
          setDeviceParam(i, ENbyOtaConSultFlag, &flag);
      }
  }else if(my_transport_role(FTYPE_OTA) == CONSUMPTION_ROLE){//消费者
      setThisParam(ENbyOtaRequestFlag, &flag);
      setThisParam(ENbyOtaRequestKeyValue, request_keyvalue);
      setThisParam(ENbyOtaConfirmFlag, &flag);
      setThisParam(ENbyOtaConfirmKeyValue, confirm_keyvalue);
#ifdef RFM_DEVICE
      stop_timeout_to_confirm_Timer();
      stop_no_rcv_timeout_Timer();
      if(ptr_last_file){
          sl_free(ptr_last_file);
          ptr_last_file = NULL;
          last_file_len = 0;
      }
      if(ptr_verify_code){
          sl_free(ptr_verify_code);
          ptr_verify_code = NULL;
      }
#endif
  }
//公共
  setThisParam(ENbyTransFileType, &file_type);
  setThisParam(ENbyOtaUpdatemeIDNum, &num);
  setThisParam(ENbyOtaUpdatemeID, id_buf);
  setThisParam(ENbyOtaConSultKeyValue, consult_keyvalue);
  setThisParam(ENbyWriteFileLinkIdx, &idx);
  setThisParam(ENbyReadFileLinkIdx, &idx);
  file_cache_link_delte(FILE_LINK_1);
}

int get_file_ctrl_duty(unsigned char *duty)
{
  if(!duty){
      return -1;
  }
  unsigned char keyvalue[OTA_CONSULT_KEYVALUE_LENGTH] = {0x00};
  getThisParam(ENbyOtaConSultKeyValue, keyvalue); //key[0] len[1] ctrl [2]
  memcpy(duty, &keyvalue[2], 1);
  return 0;
}

int get_file_file_size(unsigned char *file_size)
{
  if(!file_size){
      return -1;
  }
  unsigned char keyvalue[OTA_CONSULT_KEYVALUE_LENGTH] = {0x00};
  getThisParam(ENbyOtaConSultKeyValue, keyvalue); //key[0] len[1] ctrl [2] ftype[3] size[4-7]
  memcpy(file_size, &keyvalue[4], 4);
  return 0;
}

int get_file_page_size(unsigned char *page_size)
{
  if(!page_size){
      return -1;
  }
  unsigned char keyvalue[OTA_CONSULT_KEYVALUE_LENGTH] = {0x00};
  getThisParam(ENbyOtaConSultKeyValue, keyvalue); //key[0] len[1] ctrl [2] ftype[3] size[4-7] page[8]
  //TODO 根据枚举值和报文最大值，动态变化page_size
  page_size[0] = 224;
  //memcpy(page_size, &keyvalue[8], 1);
  return 0;
}

int get_file_sha256_code(unsigned char *sha256_code)
{
  (void)sha256_code;
  return 0;
}

FILE_TRANSPORT_ROLE_E my_transport_role(unsigned char type)
{
#ifdef HUB_DEVICE
  if(type == FTYPE_OTA){
      return PRODUCTION_ROLE;
  }
#else
  if(type == FTYPE_OTA){
      return CONSUMPTION_ROLE;
  }
#endif
  return UNKNOWN_ROLE;
}

int get_blockid_by_pageid(unsigned char *pageid)
{
  int id = 0;
  int blockid = 0;
  id = (pageid[0] << 8) + pageid[1];
  blockid = ((id % EACH_BLOCK_HAVE_MAX_PAGE_NUM) ?
      ((id)/EACH_BLOCK_HAVE_MAX_PAGE_NUM + 1) : ((id)/EACH_BLOCK_HAVE_MAX_PAGE_NUM));
  return blockid; //1-32块1，33-64块2。。。
}

int filepayload_cache_to_file_link(unsigned char *payload, int payload_len)
{
  cache_page_file_t file;
  int iret = 0;
  unsigned char write_idx = 0;
  unsigned char page_size = 0;

  get_file_page_size(&page_size);
  file.data_len = payload_len - 6;
  if(file.data_len == 0 || file.data_len > page_size){
      if(file_log_enable){
          APP_PRINTF("file page len error\r\n");
      }
      return 0xff;
  }
  file.block_id = get_blockid_by_pageid(payload);
  file.page_id[0] = payload[0];
  file.page_id[1] = payload[1];
  memcpy(file.data, &payload[2], file.data_len + 4);
#ifdef HUB_DEVICE
  product_page_id = (file.page_id[0] << 8) + file.page_id[1]; //更新product_page_id
  getThisParam(ENbyWriteFileLinkIdx, &write_idx);
#else
  write_idx = FILE_LINK_1;
#endif
  iret = file_cache_link_push(write_idx, (unsigned char *)&file, sizeof(cache_page_file_t));
#ifdef HUB_DEVICE
  if(!iret){
      ota_update_production_progress(write_idx);
      if(file_log_enable){
          APP_PRINTF("@0x%08x: pageId[%d],pageLen[%d]:",
                     (((file.page_id[0] << 8) + file.page_id[1]) - 1)*224, ((file.page_id[0]<< 8) + file.page_id[1]),
                     file.data_len);
          if(file.data_len < page_size){
              for(int i = 0; i < file.data_len; i++){
                  APP_PRINTF("%02x ",file.data[i]);
              }
          }else{
              for(int i = 0; i < 16; i++){
                  APP_PRINTF("%02x ",file.data[i]);
              }
          }
          APP_PRINTF("\r\n");
          APP_PRINTF("remain_p_num: f %d, b(%d) %d\r\n",
                     product_record.remain_f_p_num, write_idx, product_record.remain_b_p_num[write_idx]);
      }
  }
#endif
  return iret;
}

bool chcek_block_match_by_pageid(unsigned char *pageid)
{
  int block_id = 0;
  block_id = get_blockid_by_pageid(pageid);
#ifdef HUB_DEVICE
  if(get_ota_production_blockid() == block_id){
      return true;
  }
#else
  int i = 0;
  for(i = 0; i < 5; i++){
      if(custom_record.block_info[i].block_id == block_id){
          return true;
      }
  }
#endif
  return false;
}

bool chcek_file_is_exist_by_pageid(unsigned char *pageid)
{
#ifdef HUB_DEVICE
#if(0) //不再根据判断队列和历史队列里是否存在相同的pageid来判断有没有收到过该报文
  unsigned char write_idx = 0;
  getThisParam(ENbyWriteFileLinkIdx, &write_idx);
  if(check_file_is_exist_in_filelink(pageid, write_idx)){
      return true;
  }
#else //改成根据ID从小到大的原则判断是否收到过
  int id = 0;
  id = (pageid[0] << 8) + pageid[1];
  if(product_page_id >= id){ //意味着该报文已收到
      return true;
  }else{
      //product_page_id = id; 确认报文有效，再更新product_page_id
  }
#endif
#else
  int page_id = 0;
  int block_id = 0;
  int i = 0;
  unsigned char byte_idx = 0;
  unsigned char bit_idx = 0;
  unsigned char page_id_temp = 0;
  unsigned char min_id = 0xff;
#if(0)
  if(!chcek_block_match_by_pageid(pageid)){  //在记录里没有找到对应的块id，认为这页文件没收到过，
      return false;                          //但是可能对应的块信息已经被删除了，先去掉这部分判断
  }
#endif
  block_id = get_blockid_by_pageid(pageid);
  for(i = 0; i < 5; i++){
      if(custom_record.block_info[i].block_id == block_id){
          break;
      }
      if(custom_record.block_info[i].block_id < min_id){
          min_id = custom_record.block_info[i].block_id;
      }
  }
  if(i == 5){ //当前记录里没有文件的块信息，再判断一下 以前有没有收到过
      return (block_id < min_id)? (true):(false);
  }
  page_id = (pageid[0] << 8) + pageid[1];
  page_id_temp = (page_id - ((block_id - 1)*EACH_BLOCK_HAVE_MAX_PAGE_NUM)- 1);

  byte_idx = page_id_temp /8;
  bit_idx = page_id_temp %8;

  if(custom_record.block_info[i].b_result_info[byte_idx] & (1 << bit_idx)){
      return true;
  }
#endif
  return false;
}

bool check_file_crc32_is_sample(unsigned char *file,int file_len,
                                unsigned char *crc32_buf, int crc32_len)
{
  if(!file || !file_len || !crc32_buf || crc32_len != 4){
      return false;
  }

  unsigned int crc32_value = 0;
  crc32_value = get_msg_crc32(file, file_len);

  if(((crc32_value >> 24) & 0xff) != crc32_buf[0] ||
      ((crc32_value >> 16) & 0xff) != crc32_buf[1] ||
      ((crc32_value >> 8) & 0xff) != crc32_buf[2] ||
      ((crc32_value) & 0xff) != crc32_buf[3]){
      return false;
  }
  return true;
}

int creat_ota_start_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_START;
  return file_evt_link_push(&evt);
}

int creat_ota_abort_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_ABORT;
  return file_evt_link_push(&evt);
}

int creat_ota_finish_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_FINISH;
  return file_evt_link_push(&evt);
}

int creat_ota_wait_finish_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_WAIT_FINISH;
  return file_evt_link_push(&evt);
}

int creat_ota_wait_timeout_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_WAIT_TIMEOUT;
  return file_evt_link_push(&evt);
}

int creat_ota_tx_notify_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_TX_NOTIFY;
  return file_evt_link_push(&evt);
}

int creat_ota_tx_file_page_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_TX_FILE;
  return file_evt_link_push(&evt);
}

int creat_ota_tx_file_check_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_TX_CHECK;
  return file_evt_link_push(&evt);
}

int creat_ota_rx_file_page_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_RCV_FILE;
  return file_evt_link_push(&evt);
}

int creat_ota_rx_file_check_event(void)
{
  FILE_EVENT_E evt;
  evt = FILE_EVENT_RCV_CHECK;
  return file_evt_link_push(&evt);
}


